How can I use the skipper ascii::space WITHOUT skipping eol?
Asked Answered
S

1

10

I have to use boost::spirit for parsing, and I want use phrase_parse function :

qi::phrase_parse(str.begin(), str.end(), grammar, ascii::space - qi::eol); 

But the fourth term (ascii::space - qi::eol), isnt allowed by my compiler. How can I use the skipper ascii::space WITHOUT skipping eol ?

Saturnalia answered 5/5, 2012 at 20:38 Comment(4)
What exactly is the problem that the compiler has with ascii::space - qi::eol? It'll make a big difference in terms of possible solutions.Tea
Possible duplicate of #2429985Yadirayaeger
@rhalbersma: But it seems no compilable solution is given there.Frowst
In the "possible duplicate", the solution is ascii::space - eol as a skipper, but "- eol" isnt allowed, thats my problem, I want skip ascii::space but not qi::eolSaturnalia
C
16

The simplest answer is

qi::phrase_parse(str.begin(), str.end(), grammar, ascii::blank); 

Of course, it depends on your grammar too: if it expects a specific skipper class you might need to change that. See below for a generic way to handle that (although you could just specify qi::blank_type for a Grammar that should only accept qi::blank).

The sample handles arbitrary skippers too.

Other hints

Spirit has several directives that influence the use of skippers:

  • qi::lexeme

    will parse the sub-expression regardless of skipper (useful for e.g. string literals in a grammar)

  • qi::raw

    will return the raw source iterator range, meaning that skipped input will be included in the result

  • qi::no_skip, qi::skip

    can be used to explicitely change the type of skipper used for the subexpression

Recommended reading

The Boost Spirit site has a nice article about things like this

Generic sample

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

template <typename It, typename Skipper>
    struct parser : qi::grammar<It, Skipper>
{
    parser() : parser::base_type(start)
    {
        start = *qi::int_;
    }

  private:
    qi::rule<It, Skipper> start;
};

template <typename C, typename Skipper>
    void doParse(const C& input, const Skipper& skipper)
{
    auto f(std::begin(input)), l(std::end(input));

    parser<decltype(f), Skipper> p;
    bool ok = qi::phrase_parse(f,l,p,skipper);

    if (ok)   
        std::cout << "parse success\n";
}

int main()
{
    const std::string input = "1 2 3 4";
    doParse(input, qi::blank);
    doParse(input, qi::space);
    doParse(input, ~qi::char_("0-9"));
}
Charlean answered 6/5, 2012 at 10:10 Comment(3)
+1 exactly what I was looking for to glue together a bunch of mini-parsers (that only handle one line at a time)Huebner
Where does the Skipper go if the rule takes an output type (like std::string())?Iain
The parenthesis is really important "(although you could just specify qi::blank_type for a Grammar that should only accept qi::blank)." Although something in fishy because now I have to change all my grammars to qi::blank_type even though the subtokens do not need to know about eol. I guess it is because I don't think like a spiriter yet.Neoterism

© 2022 - 2024 — McMap. All rights reserved.